import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JavaGenerator{

	// private static final String URL = "jdbc:mysql://192.168.1.2:3306/yls-dev?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&serverTimezone=GMT%2B8";
	// private static final String USER_NAME = "dtis";
	// private static final String PASS_WORD = "dtis1234";

	private static final String URL = "jdbc:mysql://127.0.0.1:3306/yls-dev?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&serverTimezone=GMT%2B8";
	private static final String USER_NAME = "root";
	private static final String PASS_WORD = "root";

	private static final String DRIVER_NAME = "com.mysql.cj.jdbc.Driver";

	private static final String BASE_PATH = System.getProperty("user.dir") + "/src/main/java/";

	// 定义默认支持的表前缀
	private static final String[] DEFAULT_TABLE_PREFIXES = {"tb_", "ds_", "mk_"};

	public static void main(String[] args) {
		ArrayList<String> searchProperties = new ArrayList<>();
		// 这里可以添加需要搜索的属性，如果留空，将生成全部字段
		// 示例：添加用户ID字段作为搜索属性
		searchProperties.add("userId");

		// 示例1：使用默认前缀mk_ (不指定前缀参数，自动识别)
		createOneEntityCode("com.yls", "ds_user", "用户信息", searchProperties, null);

		// 其他示例（已注释）
		// 示例2：使用tb_前缀 (不指定前缀参数，自动识别)
		// createOneEntityCode("com.yls", "tb_project", "项目信息", searchProperties, null);

		// 示例3：使用ds_前缀 (不指定前缀参数，自动识别)
		// createOneEntityCode("com.yls", "ds_user", "用户信息", searchProperties, null);

		// 示例4：指定自定义前缀
		// createOneEntityCode("com.yls", "custom_product", "产品信息", searchProperties, "custom_");

		// 示例5：动态添加自定义前缀到默认列表中，然后使用
		// addTablePrefix("app_");
		// createOneEntityCode("com.yls", "app_config", "应用配置", searchProperties);
	}

	/**
	 * 生成1个表的entity，mapper，xml，service,serviceImpl,controller (使用默认前缀)
	 *
	 * @param parentPackage    父包名
	 * @param tableName        数据库表名，支持默认前缀
	 * @param name             业务名称
	 * @param searchProperties 列表需要查询的参数，和entity属性保持一致
	 */
	private static void createOneEntityCode(String parentPackage, String tableName, String name, List<String> searchProperties) {
		createOneEntityCode(parentPackage, tableName, name, searchProperties, null);
	}

	/**
	 * 生成1个表的entity，mapper，xml，service,serviceImpl,controller
	 *
	 * @param parentPackage    父包名
	 * @param tableName        数据库表名，支持多种前缀
	 * @param name             业务名称
	 * @param searchProperties 列表需要查询的参数，和entity属性保持一致
	 * @param tablePrefix      指定表前缀，为null时自动识别默认支持的前缀
	 */
	private static void createOneEntityCode(String parentPackage, String tableName, String name, List<String> searchProperties, String tablePrefix) {
		if (StringUtils.isBlank(tableName)) {
			log.warn("请输入数据库表名");
			return;
		}

		String prefix = null;
		// 如果指定了表前缀，则使用指定的前缀
		if (StringUtils.isNotBlank(tablePrefix)) {
			if (!tableName.startsWith(tablePrefix)) {
				log.warn("数据库表名必须以" + tablePrefix + "开始");
				return;
			}
			prefix = tablePrefix;
		} else {
			// 否则检查是否以默认支持的前缀开头
			boolean validPrefix = false;
			for (String defaultPrefix : DEFAULT_TABLE_PREFIXES) {
				if (tableName.startsWith(defaultPrefix)) {
					validPrefix = true;
					prefix = defaultPrefix;
					break;
				}
			}

			if (!validPrefix) {
				log.warn("数据库表名必须以下列前缀之一开始：" + String.join(", ", DEFAULT_TABLE_PREFIXES));
				return;
			}
		}

		// 生成entity,mapper,xml
		createMybatisCode(tableName, parentPackage, prefix);
		// 获取生成的entity类名
		String entityName = tableName.substring(prefix.length()); // 先去掉前缀
		String camel = camel(entityName); // 再进行驼峰转换

		// 确保首字母大写
		camel = camel.substring(0, 1).toUpperCase() + camel.substring(1);

		createGwxCode(parentPackage, camel, name, searchProperties);
		log.info("------------生成完成-----------");
	}

	/**
	 * 只生成 entity，mapper，xml
	 *
	 * @param tableName     表名
	 * @param parentPackage 父包名
	 * @param tablePrefix   表前缀
	 */
	private static void createMybatisCode(String tableName, String parentPackage, String tablePrefix) {
		log.info("生成Mybatis代码，表名：" + tableName + "，前缀：" + tablePrefix);

		// 代码生成器
		AutoGenerator mpg = new AutoGenerator();
		// 数据源配置
		DataSourceConfig dsc = new DataSourceConfig();
		dsc.setDbType(DbType.MYSQL);
		dsc.setUrl(URL);
		dsc.setDriverName(DRIVER_NAME);
		dsc.setUsername(USER_NAME);
		dsc.setPassword(PASS_WORD);
		// 数据源配置
		dsc.setTypeConvert(new MySqlTypeConvert() {
			@Override
			public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
				// tinyint转换成byte
				if (fieldType.toLowerCase().contains("tinyint")) {
					return DbColumnType.BYTE;
				}
				return super.processTypeConvert(globalConfig, fieldType);
			}

		});
		mpg.setDataSource(dsc);

		// 包配置
		PackageConfig pc = new PackageConfig();
		pc.setParent(parentPackage);
		mpg.setPackageInfo(pc);

		// 不生成controller,service;
		TemplateConfig tc = new TemplateConfig();
		tc.setController("");
		tc.setService("");
		tc.setServiceImpl("");
		mpg.setTemplate(tc);

		// 全局配置
		GlobalConfig gc = new GlobalConfig();
		gc.setOpen(false);
		gc.setAuthor("yishan");
		gc.setSwagger2(true);
		gc.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
		gc.setFileOverride(false);// 是否覆盖同名文件，默认是false
		gc.setActiveRecord(false);// 不需要ActiveRecord特性的请改为false
		gc.setEnableCache(false);// XML 二级缓存
		gc.setBaseResultMap(true);// XML ResultMap
		gc.setBaseColumnList(false);// XML columList
		mpg.setGlobalConfig(gc);

		// 选择 freemarker 引擎，默认 Veloctiy
		mpg.setTemplateEngine(new FreemarkerTemplateEngine());

		// 数据库表配置
		StrategyConfig sc = new StrategyConfig();
		sc.setCapitalMode(true);
		sc.setNaming(NamingStrategy.underline_to_camel);
		sc.setEntityLombokModel(true);
		sc.setControllerMappingHyphenStyle(true);
		// 生成@RestController控制器
		sc.setRestControllerStyle(false);
		// 驼峰转连字符串
		sc.setControllerMappingHyphenStyle(true);
		sc.setTablePrefix(new String[] { tablePrefix });// 设置表前缀
		sc.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
		if (StringUtils.isNotBlank(tableName)) {
			String[] tableNames = { tableName };
			sc.setInclude(tableNames); // 需要生成的表
		}
		sc.setRestControllerStyle(true);

		// 设置策略配置到生成器中
		mpg.setStrategy(sc);

		log.info("准备生成代码，表名：" + tableName + "，表前缀：" + tablePrefix);

		// 执行生成
		mpg.execute();

		log.info("Mybatis代码生成完成");
	}

	/**
	 * 生成代码
	 */
	/**
	 * @param parentPackage    父包名
	 * @param className        数据库生成的entity类名
	 * @param name             业务名称
	 * @param searchProperties 列表需要查询的参数，和entity属性保持一致
	 */
	private static void createGwxCode(String parentPackage, String className, String name, List<String> searchProperties) {
		String packagePath = parentPackage.replaceAll("\\.", "/") + "/";
		createGwxUtils(parentPackage, packagePath + "utils/");
		String entityClassName = System.getProperty("user.dir") + "/src/main/java/" + packagePath + "/entity/"
				+ className + ".java";
		javaCodeToClass(entityClassName);
		createGwxDTO(parentPackage, className, name, packagePath + "dto/", searchProperties);
		createGwxReq(parentPackage, className, name, packagePath + "req/", searchProperties);
		createGwxIService(parentPackage, className, name, packagePath + "service/");
		createGwxServiceImpl(parentPackage, className, name, packagePath + "service/impl/");
		createGwxController(parentPackage, className, name, packagePath + "controller/");
		createGwxVue(parentPackage, className, name, packagePath + "vue/");
	}

	/**
	 * 生成req
	 *
	 * @param parentPackage    父包名
	 * @param className        数据库生成的entity类名
	 * @param name             业务名称
	 * @param packagePath      代码包路径
	 * @param searchProperties 列表需要查询的参数，和entity属性保持一致
	 */
	private static void createGwxReq(String parentPackage, String className, String name, String packagePath,
			List<String> searchProperties) {

		// 获取模板文件路径
		String gwxTemplatePath = System.getProperty("user.dir") + "/src/main/resources/gwxTemplate/GwxTemplateReq.txt";
		// 生成ReqName
		String reqName = className + "Req.java";

		// 生成req路径
		File folder = new File(BASE_PATH + packagePath);
		if (!folder.exists() && !folder.isDirectory()) {
			folder.mkdirs();
		}

		String gwxTemplateBaseReqPath = System.getProperty("user.dir") + "/src/main/resources/gwxTemplate/BaseReq.txt";
		String gwxBaseReqPath = BASE_PATH + packagePath + "BaseReq.java";
		createUtils(packagePath, gwxTemplateBaseReqPath, gwxBaseReqPath);
		javaCodeToClass(gwxBaseReqPath);
		String reqPath = BASE_PATH + packagePath + reqName;
		File file = new File(reqPath);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			log.warn(reqPath + "已存在");
			return;
		}
		String classNameFirstLower = className.substring(0, 1).toLowerCase() + className.substring(1);
		// 获取模板文件内容
		final List<String> newLineList = new ArrayList<String>();
		List<String> gwxTemplateContentLineList = readList(gwxTemplatePath);
		for (String line : gwxTemplateContentLineList) {
			// 替换固定变量
			String replaceAll = line.replaceAll("gwxTemplate", classNameFirstLower).replaceAll("GwxTemplate", className)
					.replaceAll("业务名称", name);
			newLineList.add(replaceAll);
		}
		// 查找属性填充
		if (CollectionUtils.isNotEmpty(searchProperties)) {

			// 通过反射获取类对象
			Class<?> forName = null;
			String entityClassName = parentPackage.replaceAll("/", ".") + ".entity." + className;
			try {
				forName = Class.forName(entityClassName);
			} catch (ClassNotFoundException e) {
				log.warn(entityClassName + "类名不存在");
				return;
			}
			// 去掉最后一个"}"
			newLineList.remove(newLineList.size() - 1);
			// 拼接属性
			final Class<?> finalClassName = forName;
			searchProperties.stream().forEach(searchPropertie -> {
				Field field = null;
				try {
					field = finalClassName.getDeclaredField(searchPropertie);
					Class<?> type = field.getType();
					String fieldTypeName = type.getName();
					String[] split = fieldTypeName.split("\\.");
					fieldTypeName = split[split.length - 1];

					ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
					newLineList.add("\t@ApiModelProperty(\"" + annotation.value() + "\")");
					newLineList.add("\tprivate " + fieldTypeName + " " + searchPropertie + ";");
					newLineList.add("");
				} catch (Exception e) {
					log.warn(entityClassName + "_" + searchPropertie + "属性不存在");
					return;
				}

			});
			// 拼接最后一个"}"
			newLineList.add("}");
		}

		String replaceStr = packagePath.substring(0, packagePath.length() - 1).replace("/", ".");
		newLineList.set(0, "package " + replaceStr + ";");
		writeList(newLineList, reqPath);
		javaCodeToClass(reqPath);
	}

	/**
	 * 生成utils
	 *
	 * @param parentPackage    父包名
	 * @param className        数据库生成的entity类名
	 * @param name             业务名称
	 * @param packagePath      代码包路径
	 * @param searchProperties 列表需要查询的参数，和entity属性保持一致
	 */
	private static void createGwxUtils(String parentPackage, String packagePath) {

		// 获取模板文件路径
		String gwxTemplateDateUtilsPath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/DateUtils.txt";
		String gwxTemplateMyAssertPath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/MyAssert.txt";
		String gwxTemplateTarsPluralismExceptionPath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/TarsPluralismException.txt";
		String gwxTemplateTarsPluralismExceptionConfigPath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/TarsPluralismExceptionConfig.txt";

		String gwxTemplateHttpResponsePath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/HttpResponse.txt";
		String gwxTemplateHttpResponseEntityPath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/HttpResponseEntity.txt";
		String gwxTemplateListHttpResponseModelPath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/ListHttpResponseModel.txt";

		String gwxDateUtilsPath = BASE_PATH + packagePath + "DateUtils.java";
		String gwxMyAssertPath = BASE_PATH + packagePath + "MyAssert.java";
		String gwxTarsPluralismExceptionPath = BASE_PATH + packagePath + "TarsPluralismException.java";
		String gwxTarsPluralismExceptionConfigPath = BASE_PATH + packagePath + "TarsPluralismExceptionConfig.java";

		String gwxHttpResponsePath = BASE_PATH + packagePath + "HttpResponse.java";
		String gwxHttpResponseEntityPath = BASE_PATH + packagePath + "HttpResponseEntity.java";
		String gwxListHttpResponseModelPath = BASE_PATH + packagePath + "ListHttpResponseModel.java";

		// 生成req路径
		File folder = new File(BASE_PATH + packagePath);
		if (!folder.exists() && !folder.isDirectory()) {
			folder.mkdirs();
		}
		createUtils(packagePath, gwxTemplateDateUtilsPath, gwxDateUtilsPath);
		createUtils(packagePath, gwxTemplateMyAssertPath, gwxMyAssertPath);
		createUtils(packagePath, gwxTemplateTarsPluralismExceptionPath, gwxTarsPluralismExceptionPath);
		createUtils(packagePath, gwxTemplateTarsPluralismExceptionConfigPath, gwxTarsPluralismExceptionConfigPath);

		createUtils(packagePath, gwxTemplateHttpResponsePath, gwxHttpResponsePath);
		createUtils(packagePath, gwxTemplateHttpResponseEntityPath, gwxHttpResponseEntityPath);
		createUtils(packagePath, gwxTemplateListHttpResponseModelPath, gwxListHttpResponseModelPath);
	}

	private static void createUtils(String packagePath, String gwxTemplateHttpResponsePath,
			String gwxHttpResponsePath) {
		File file3 = new File(gwxHttpResponsePath);
		if (!file3.exists()) {
			try {
				file3.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			log.warn(gwxHttpResponsePath + "已存在");
			return;
		}
		// 获取模板文件内容
		List<String> gwxTemplateContentLineList = readList(gwxTemplateHttpResponsePath);
		String replaceStr = packagePath.substring(0, packagePath.length() - 1).replace("/", ".");
		gwxTemplateContentLineList.set(0, "package " + replaceStr + ";");
		writeList(gwxTemplateContentLineList, gwxHttpResponsePath);
	}

	/**
	 * 生成dto
	 *
	 * @param parentPackage    父包名
	 * @param className        数据库生成的entity类名
	 * @param name             业务名称
	 * @param packagePath      代码包路径
	 * @param searchProperties 列表需要查询的参数，和entity属性保持一致
	 */
	private static void createGwxDTO(String parentPackage, String className, String name, String packagePath,
			List<String> searchProperties) {

		// 获取模板文件路径
		String gwxTemplatePath = System.getProperty("user.dir") + "/src/main/resources/gwxTemplate/GwxTemplateDTO.txt";

		// 生成ReqName
		String reqName = className + "DTO.java";

		// 生成req路径
		File folder = new File(BASE_PATH + packagePath);
		if (!folder.exists() && !folder.isDirectory()) {
			folder.mkdirs();
		}

		String reqPath = BASE_PATH + packagePath + reqName;
		File file = new File(reqPath);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			log.warn(reqPath + "已存在");
			return;
		}
		String classNameFirstLower = className.substring(0, 1).toLowerCase() + className.substring(1);
		// 获取模板文件内容
		List<String> newLineList = new ArrayList<String>();
		List<String> gwxTemplateContentLineList = readList(gwxTemplatePath);
		for (String line : gwxTemplateContentLineList) {
			// 替换固定变量
			String replaceAll = line.replaceAll("gwxTemplate", classNameFirstLower).replaceAll("GwxTemplate", className)
					.replaceAll("业务名称", name);
			newLineList.add(replaceAll);
		}
		// 查找属性填充
		// 获取entity类
		Class<?> forName = null;
		String entityClassName = parentPackage.replaceAll("/", ".") + ".entity." + className;
		try {
			log.info("尝试加载entity类：" + entityClassName);
			forName = Class.forName(entityClassName);
			log.info("成功加载entity类：" + entityClassName);
		} catch (ClassNotFoundException e) {
			log.warn(entityClassName + "类名不存在，请确认表名和前缀是否正确");
			return;
		}

		// 去掉最后一个"}"
		newLineList.remove(newLineList.size() - 1);

		// 拼接属性
		Field[] declaredFields = forName.getDeclaredFields();
		log.info("entity类字段数量：" + declaredFields.length);
		for (Field field : declaredFields) {
			String fieldName = field.getName();
			try {
				if ("serialVersionUID".equals(fieldName)) {
					continue;
				}
				Class<?> type = field.getType();
				String fieldTypeName = type.getName();
				String[] split = fieldTypeName.split("\\.");
				fieldTypeName = split[split.length - 1];
				if ("Long".equals(fieldTypeName) || "LocalDateTime".equals(fieldTypeName)) {
					fieldTypeName = "String";
				}
				ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
				String annotationValue = annotation != null ? annotation.value() : fieldName;

				newLineList.add("\t@NotNull(message = \"" + annotationValue + "不能为空\")");
				newLineList.add("\t@ApiModelProperty(\"" + annotationValue + "\")");
				newLineList.add("\tprivate " + fieldTypeName + " " + fieldName + ";");
				newLineList.add("");
				log.info("添加字段：" + fieldName + ", 类型：" + fieldTypeName);
			} catch (Exception e) {
				log.warn(entityClassName + "_" + fieldName + "拷贝失败: " + e.getMessage());
			}
		}

		// 拼接最后一个"}"
		newLineList.add("}");

		String replaceStr = packagePath.substring(0, packagePath.length() - 1).replace("/", ".");
		newLineList.set(0, "package " + replaceStr + ";");
		writeList(newLineList, reqPath);
		javaCodeToClass(reqPath);
	}

	/**
	 * 生成serviceImpl
	 *
	 * @param className   数据库生成的entity类名
	 * @param name        业务名称
	 * @param packagePath 代码包路径
	 */
	private static void createGwxServiceImpl(String parentPackage, String className, String name, String packagePath) {
		// 获取模板文件路径
		String gwxTemplatePath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/GwxTemplateServiceImpl.txt";

		// 生成serviceName
		String serviceName = className + "ServiceImpl.java";

		// 生成service路径
		File folder = new File(BASE_PATH + packagePath);
		if (!folder.exists() && !folder.isDirectory()) {
			folder.mkdirs();
		}
		String servicePath = BASE_PATH + packagePath + serviceName;
		File file = new File(servicePath);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			log.warn(servicePath + "已存在");
			return;
		}

		// 获取entity类
		Class<?> entityClass = null;
		String entityClassPath = parentPackage + ".entity." + className;

		try {
			entityClass = Class.forName(entityClassPath);
		} catch (ClassNotFoundException e) {
			log.warn(entityClassPath + "类名不存在");
			return;
		}

		// 获取req类
		Class<?> reqClass = null;
		String reqClassPath = parentPackage + ".req." + className + "Req";

		try {
			reqClass = Class.forName(reqClassPath);
		} catch (ClassNotFoundException e) {
			log.warn(reqClassPath + "类名不存在");
			return;
		}
		// 获取dto类
		Class<?> dtoClass = null;
		String dtoClassPath = parentPackage + ".dto." + className + "DTO";

		try {
			dtoClass = Class.forName(dtoClassPath);
		} catch (ClassNotFoundException e) {
			log.warn(dtoClassPath + "类名不存在");
			return;
		}

		String classNameFirstLower = className.substring(0, 1).toLowerCase() + className.substring(1);
		// 获取模板文件内容
		List<String> newLineList = new ArrayList<String>();
		List<String> gwxTemplateContentLineList = readList(gwxTemplatePath);
		for (String line : gwxTemplateContentLineList) {
			// 替换固定变量
			String replaceAll = line.replaceAll("gwxTemplate", classNameFirstLower).replaceAll("GwxTemplate", className)
					.replaceAll("业务名称", name).replaceAll("com.gwx", parentPackage);
			;
			String dtoStr = classNameFirstLower + "DTO";
			// STARTENTITYSETDTO赋值
			if ("\t\t\tSTARTENTITYSETDTO".equals(replaceAll)) {
				// 1创建dto
				String createDTOStr = "\t\t\t" + dtoClass.getSimpleName() + " " + dtoStr + " = new "
						+ dtoClass.getSimpleName() + "();";
				newLineList.add(createDTOStr);
				// 开始赋值
				Field[] declaredFields = dtoClass.getDeclaredFields();
				for (Field field : declaredFields) {
					String fieldName = field.getName();
					try {
						String setStr = "\t\t\t";
						Field entityField = entityClass.getDeclaredField(fieldName);
						Class<?> type = entityField.getType();
						String fieldTypeName = type.getName();
						String[] split = fieldTypeName.split("\\.");
						fieldTypeName = split[split.length - 1];
						String fieldNameFirstToUpper = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
						if ("Long".equals(fieldTypeName)) {
							setStr += dtoStr + ".set" + fieldNameFirstToUpper + "(String.valueOf(x.get"
									+ fieldNameFirstToUpper + "()));";
						} else if ("LocalDateTime".equals(fieldTypeName)) {
							setStr += dtoStr + ".set" + fieldNameFirstToUpper + "(x.get" + fieldNameFirstToUpper
									+ "() == null ? null : x.get" + fieldNameFirstToUpper + "().format(DateUtils.DF));";
						} else {
							setStr += dtoStr + ".set" + fieldNameFirstToUpper + "(x.get" + fieldNameFirstToUpper
									+ "());";
						}
						newLineList.add(setStr);
					} catch (Exception e) {
						log.warn(dtoClass.getName() + "_" + fieldName + "拷贝失败");
						return;
					}
				}
				newLineList.add("list.add(" + dtoStr + ");");
			}
			// STARTDTOSETENTITY赋值
			else if ("\t\tSTARTDTOSETENTITY".equals(replaceAll)) {
				// 开始赋值
				Field[] declaredFields = dtoClass.getDeclaredFields();
				for (Field field : declaredFields) {
					String fieldName = field.getName();
					if ("id".equals(fieldName) || "is_active".equals(fieldName) || "create_time".equals(fieldName)
							|| "update_time".equals(fieldName)) {
						continue;
					}
					try {
						String setStr = "\t\t";
						Field entityField = entityClass.getDeclaredField(fieldName);
						Class<?> type = entityField.getType();
						String fieldTypeName = type.getName();
						String[] split = fieldTypeName.split("\\.");
						fieldTypeName = split[split.length - 1];
						String fieldNameFirstToUpper = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
						if ("Long".equals(fieldTypeName)) {
							setStr += classNameFirstLower + ".set" + fieldNameFirstToUpper + "(Long.valueOf(dto.get"
									+ fieldNameFirstToUpper + "()));";
						} else if ("LocalDateTime".equals(fieldTypeName)) {
							setStr += classNameFirstLower + ".set" + fieldNameFirstToUpper + "(dto.get"
									+ fieldNameFirstToUpper + "() == null ? null : LocalDateTime.parse(dto.get"
									+ fieldNameFirstToUpper + "(), DateUtils.DF));";
						} else {
							setStr += classNameFirstLower + ".set" + fieldNameFirstToUpper + "(dto.get"
									+ fieldNameFirstToUpper + "());";
						}
						newLineList.add(setStr);
					} catch (Exception e) {
						log.warn(dtoClass.getName() + "_" + fieldName + "拷贝失败");
						return;
					}
				}
			}
			// STARTQUERY赋值
			else if ("\t\tSTARTQUERY".equals(replaceAll)) {
				// 开始赋值
				Field[] declaredFields = reqClass.getDeclaredFields();
				for (Field field : declaredFields) {
					String fieldName = field.getName();
					try {
						Field entityField = entityClass.getDeclaredField(fieldName);
						Class<?> type = entityField.getType();
						String fieldTypeName = type.getName();
						String[] split = fieldTypeName.split("\\.");
						fieldTypeName = split[split.length - 1];
						String fieldNameFirstToUpper = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
						if ("String".equals(fieldTypeName)) {
							String str = "\t\tif (StringUtils.isNotBlank(req.get" + fieldNameFirstToUpper + "())) {";
							newLineList.add(str);
							String str2 = "\t\t\tquery.lambda().eq(" + className + "::get" + fieldNameFirstToUpper
									+ ", req.get" + fieldNameFirstToUpper + "());";
							newLineList.add(str2);
							newLineList.add("\t\t}");
						} else if ("LocalDateTime".equals(fieldTypeName)) {
							// 暂时不处理
						} else {
							String str = "\t\tif (req.get" + fieldNameFirstToUpper + "() != null) {";
							newLineList.add(str);
							String str2 = "\t\t\tquery.lambda().eq(" + className + "::get" + fieldNameFirstToUpper
									+ ", req.get" + fieldNameFirstToUpper + "());";
							newLineList.add(str2);
							newLineList.add("\t\t}");
						}
					} catch (Exception e) {
						log.warn(dtoClass.getName() + "_" + fieldName + "拷贝失败");
						return;
					}
				}
			} else {
				newLineList.add(replaceAll);
			}
		}
		newLineList.set(0, "package " + packagePath.substring(0, packagePath.length() - 1).replace("/", ".") + ";");
		writeList(newLineList, servicePath);
	}

	/**
	 * 生成service
	 *
	 * @param className   数据库生成的entity类名
	 * @param name        业务名称
	 * @param packagePath 代码包路径
	 */
	private static void createGwxIService(String parentPackage, String className, String name, String packagePath) {
		// 获取模板文件路径
		String gwxTemplatePath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/IGwxTemplateService.txt";

		// 生成service接口Name
		String serviceName = "I" + className + "Service.java";

		// 生成service路径
		String servicePath = BASE_PATH + packagePath + serviceName;
		File folder = new File(BASE_PATH + packagePath);
		if (!folder.exists() && !folder.isDirectory()) {
			folder.mkdirs();
		}
		File file = new File(servicePath);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			log.warn(servicePath + "已存在");
			return;
		}
		String classNameFirstLower = className.substring(0, 1).toLowerCase() + className.substring(1);
		// 获取模板文件内容
		List<String> newLineList = new ArrayList<String>();
		List<String> gwxTemplateContentLineList = readList(gwxTemplatePath);
		for (String line : gwxTemplateContentLineList) {
			// 替换固定变量
			String replaceAll = line.replaceAll("gwxTemplate", classNameFirstLower).replaceAll("GwxTemplate", className)
					.replaceAll("业务名称", name).replaceAll("com.gwx", parentPackage);
			newLineList.add(replaceAll);
		}
		newLineList.set(0, "package " + packagePath.substring(0, packagePath.length() - 1).replace("/", ".") + ";");
		writeList(newLineList, servicePath);
	}

	/**
	 * 生成controller
	 *
	 * @param className   数据库生成的entity类名
	 * @param name        业务名称
	 * @param packagePath 代码包路径
	 */
	private static void createGwxController(String parentPackage, String className, String name, String packagePath) {
		// 获取模板文件路径
		String gwxTemplatePath = System.getProperty("user.dir")
				+ "/src/main/resources/gwxTemplate/GwxTemplateController.txt";

		// 生成Controller接口Name
		String serviceName = className + "WebController.java";

		// 生成Controller路径
		String servicePath = BASE_PATH + packagePath + serviceName;
		File folder = new File(BASE_PATH + packagePath);
		if (!folder.exists() && !folder.isDirectory()) {
			folder.mkdirs();
		}
		File file = new File(servicePath);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			log.warn(servicePath + "已存在");
			return;
		}
		String classNameFirstLower = className.substring(0, 1).toLowerCase() + className.substring(1);
		// 获取模板文件内容
		List<String> newLineList = new ArrayList<String>();
		List<String> gwxTemplateContentLineList = readList(gwxTemplatePath);
		for (String line : gwxTemplateContentLineList) {
			// 替换固定变量
			String replaceAll = line.replaceAll("gwxTemplate", classNameFirstLower).replaceAll("GwxTemplate", className)
					.replaceAll("业务名称", name).replaceAll("com.gwx", parentPackage);
			newLineList.add(replaceAll);
		}
		newLineList.set(0, "package " + packagePath.substring(0, packagePath.length() - 1).replace("/", ".") + ";");
		writeList(newLineList, servicePath);
	}

	/**
	 * 生成vue
	 *
	 * @param className   数据库生成的entity类名
	 * @param name        业务名称
	 * @param packagePath 代码包路径
	 */
	private static void createGwxVue(String parentPackage, String className, String name, String packagePath) {
		// 获取模板文件路径
		String gwxTemplatePath = System.getProperty("user.dir") + "/src/main/resources/gwxTemplate/GwxTemplateVue.txt";

		// 生成vue
		String classNameFirstLower = className.substring(0, 1).toLowerCase() + className.substring(1);
		String serviceName = classNameFirstLower + ".vue";

		// 生成vue路径
		File folder = new File(BASE_PATH + packagePath);
		if (!folder.exists() && !folder.isDirectory()) {
			folder.mkdirs();
		}
		String servicePath = BASE_PATH + packagePath + serviceName;
		File file = new File(servicePath);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			log.warn(servicePath + "已存在");
			return;
		}

		// 获取req类
		Class<?> reqClass = null;
		String reqClassPath = parentPackage + ".req." + className + "Req";

		try {
			reqClass = Class.forName(reqClassPath);
		} catch (ClassNotFoundException e) {
			log.warn(reqClassPath + "类名不存在");
			return;
		}
		// 获取dto类
		Class<?> dtoClass = null;
		String dtoClassPath = parentPackage + ".dto." + className + "DTO";

		try {
			dtoClass = Class.forName(dtoClassPath);
		} catch (ClassNotFoundException e) {
			log.warn(dtoClassPath + "类名不存在");
			return;
		}

		// 获取模板文件内容
		List<String> newLineList = new ArrayList<String>();
		List<String> gwxTemplateContentLineList = readList(gwxTemplatePath);
		for (String line : gwxTemplateContentLineList) {
			// 替换固定变量
			String replaceAll = line.replaceAll("gwxTemplate", classNameFirstLower).replaceAll("GwxTemplate", className)
					.replaceAll("业务名称", name);
			// SEARCHPARAM查询条件
			if ("SEARCHPARAM".equals(replaceAll.trim())) {

				Field[] reqFields = reqClass.getDeclaredFields();
				for (Field field : reqFields) {
					String fieldName = field.getName();
					ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
					String value = annotation.value();
					if (StringUtils.isNotBlank(value) && value.contains(":") && value.contains(".")
							&& value.contains(";")) {
						// 说明是枚举。测试类型:1.大类型;2.小类型;
						String[] split = value.split(":");
						String paramCname = split[0];
						String[] paramValues = split[1].split(";");
						newLineList.add("   <el-form-item label=\"" + paramCname
								+ "\" label-width=\"40px\" class=\"mr30 ib\"><el-select v-model=\"searchModel."
								+ fieldName + "\" style=\"width: 100px;\">");
						newLineList.add("    <el-option label=\"全部\" value=\"\"></el-option>");
						for (String indexValue : paramValues) {
							String[] valueArray = indexValue.split("\\.");
							newLineList.add("    <el-option label=\"" + valueArray[1] + "\" value=\"" + valueArray[0]
									+ "\"></el-option>");
						}
						newLineList.add("   </el-select></el-form-item>");
					} else {
						// 普通查询
						newLineList
								.add("   <el-form-item label=\"\" class=\"mr30 ib\"><el-input  v-model=\"searchModel."
										+ fieldName + "\" style=\"width: 125px;\"  placeholder=\"请输入" + value
										+ "\"></el-input></el-form-item>");
					}
				}
			}
			// EDITPARAM编辑
			else if ("EDITPARAM".equals(replaceAll.trim())) {
				Field[] dtoFields = dtoClass.getDeclaredFields();
				for (Field field : dtoFields) {
					String fieldName = field.getName();
					if ("isactive".equals(fieldName.toLowerCase()) || "inserttime".equals(fieldName.toLowerCase())
							|| "updatetime".equals(fieldName.toLowerCase())) {
						continue;
					}
					ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
					String value = annotation.value();
					if (StringUtils.isNotBlank(value) && value.contains(":") && value.contains(".")
							&& value.contains(";")) {
						// 说明是枚举。测试类型:1.大类型;2.小类型;
						String[] split = value.split(":");
						String paramCname = split[0];
						String[] paramValues = split[1].split(";");
						newLineList.add("      <el-form-item label=\"" + paramCname
								+ "\" label-width=\"40px\" class=\"mr30 ib\"><el-select v-model=\"detailModel."
								+ fieldName + "\" style=\"width: 100px;\">");
						for (String indexValue : paramValues) {
							String[] valueArray = indexValue.split("\\.");
							newLineList.add("       <el-option label=\"" + valueArray[1] + "\" value=\"" + valueArray[0]
									+ "\"></el-option>");
						}
						newLineList.add("      </el-select></el-form-item>");
					} else {
						// 普通查询
						newLineList.add("      <el-form-item label=\"" + value + "\"><el-input v-model=\"detailModel."
								+ fieldName + "\"  style=\"width: 200px;\"></el-input></el-form-item>");
					}
				}
			}
			// PARAMLIST列表
			else if ("PARAMLIST".equals(replaceAll.trim())) {
				Field[] dtoFields = dtoClass.getDeclaredFields();
				for (Field field : dtoFields) {
					String fieldName = field.getName();
					if ("id".equals(fieldName.toLowerCase()) || "isactive".equals(fieldName.toLowerCase())
							|| "inserttime".equals(fieldName.toLowerCase())
							|| "updatetime".equals(fieldName.toLowerCase())) {
						continue;
					}
					ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
					String value = annotation.value();
					if (StringUtils.isNotBlank(value) && value.contains(":") && value.contains(".")
							&& value.contains(";")) {
						// 说明是枚举。测试类型:1.大类型;2.小类型;
						String[] split = value.split(":");
						String paramCname = split[0];
						newLineList.add("   <el-table-column prop=\"" + fieldName + "\" label=\"" + paramCname
								+ "\" align='center'width=\"200\"></el-table-column>");
					} else {
						newLineList.add("   <el-table-column prop=\"" + fieldName + "\" label=\"" + value
								+ "\" align='center'width=\"200\"></el-table-column>");
					}
				}
			}
			// SEARCHPARAMMODEL查询条件model
			else if ("SEARCHPARAMMODEL".trim().equals(replaceAll.trim())) {

				Field[] reqFields = reqClass.getDeclaredFields();
				for (Field field : reqFields) {
					String fieldName = field.getName();
					ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
					String value = annotation.value();
					newLineList.add("   	" + fieldName + ":'',//" + value);
				}
			}
			// SEARCHPARAMMODEL 详情空置model
			else if ("DETAILMODEL".equals(replaceAll.trim())) {

				Field[] dtoFields = dtoClass.getDeclaredFields();
				for (Field field : dtoFields) {
					String fieldName = field.getName();
					ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
					String value = annotation.value();
					newLineList.add("   	" + fieldName + ":'',//" + value);
				}
			}
			// DETAILVALUEMODEL 详情赋值model
			else if ("DETAILVALUEMODEL".equals(replaceAll.trim())) {

				Field[] dtoFields = dtoClass.getDeclaredFields();
				for (Field field : dtoFields) {
					String fieldName = field.getName();
					ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
					String value = annotation.value();
					newLineList.add("   	" + fieldName + ":row." + fieldName + ",//" + value);
				}
			} else {
				newLineList.add(replaceAll);
			}
		}
		writeList(newLineList, servicePath);
	}

	public static List<String> readList(String path) {
		List<String> res = null;
		try {
			res = Files.lines(Paths.get(path)).collect(Collectors.toList());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return res;
	}

	public static void writeBatchNo(String batchNo, String toPath) {
		try {
			Files.write(Paths.get(toPath), batchNo.getBytes(StandardCharsets.UTF_8));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void writeList(Collection<String> data, String toPath) {
		try {
			Path path = Paths.get(toPath);
			// 如果存在先删除
			if (Files.exists(path)) {
				Files.delete(path);
			}
			Files.write(path, data, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void quickCopy(File src, File target) {
		try (FileInputStream inputStream = new FileInputStream(src);
				FileOutputStream outputStream = new FileOutputStream(target);
				FileChannel inputChannel = inputStream.getChannel(); // 得到源文件通道
				FileChannel outputChannel = outputStream.getChannel()// 得到目标文件通道
		) {
			// 将源文件数据通达连通到目标文件通道进行传输
			inputChannel.transferTo(0, inputChannel.size(), outputChannel);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 下划线转驼峰
	 *
	 * @param str
	 * @return
	 */
	public static String camel(String str) {
		// 利用正则删除下划线，把下划线后一位改成大写
		Pattern pattern = Pattern.compile("_(\\w)");
		Matcher matcher = pattern.matcher(str);
		StringBuffer sb = new StringBuffer(str);
		if (matcher.find()) {
			sb = new StringBuffer();
			// 将当前匹配子串替换为指定字符串，并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
			// 正则之前的字符和被替换的字符
			matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
			// 把之后的也添加到StringBuffer对象里
			matcher.appendTail(sb);
		} else {
			return sb.toString();
		}
		return camel(sb.toString());
	}
	/**
	 * 动态编译类到内存
	 *
	 * @param path 需要加载的类全路径
	 */
	public static void javaCodeToClass(String path) {
		// 检查文件是否存在
		File file = new File(path);
		if (!file.exists()) {
			log.warn("文件不存在，无法编译: " + path);
			return;
		}

		// 动态编译
		JavaCompiler javac = ToolProvider.getSystemJavaCompiler();

		// 检查是否成功获取到 Java 编译器
		if (javac == null) {
			System.err.println("无法找到系统 Java 编译器。请确保 JDK 已安装并配置在系统 PATH 中。");
			return;
		}

		// 设置目标目录为项目的 classes 目录
		String targetDir = System.getProperty("user.dir") + File.separator + "target" + File.separator + "classes";

		// 执行编译
		int status = javac.run(null, null, null, "-d", targetDir, path);

		// 检查编译状态
		if (status != 0) {
			System.err.println("编译失败！");
		} else {
			System.out.println("编译成功！");
		}
	}

	/**
	 * 添加自定义前缀到默认前缀列表中
	 *
	 * @param prefix 要添加的自定义前缀
	 */
	public static void addTablePrefix(String prefix) {
		if (StringUtils.isNotBlank(prefix)) {
			List<String> prefixList = new ArrayList<>(Arrays.asList(DEFAULT_TABLE_PREFIXES));
			if (!prefixList.contains(prefix)) {
				prefixList.add(prefix);
				// 反射修改DEFAULT_TABLE_PREFIXES常量值
				try {
					Field field = JavaGenerator.class.getDeclaredField("DEFAULT_TABLE_PREFIXES");
					field.setAccessible(true);

					// 移除final修饰符
					Field modifiersField = Field.class.getDeclaredField("modifiers");
					modifiersField.setAccessible(true);
					modifiersField.setInt(field, field.getModifiers() & ~java.lang.reflect.Modifier.FINAL);

					field.set(null, prefixList.toArray(new String[0]));
				} catch (Exception e) {
					log.warn("添加表前缀失败：" + e.getMessage());
				}
			}
		}
	}
}
